#include "j1939tp_config.h"
#include "rtdef.h"

#include "FreeRTOS.h"
#include "event_groups.h"
#include "cmsis_os2.h"

#include "j1939tp.h"

void can_ch0_recv_callback(const j1939_msg_info_t *info, const uint8_t *data, uint32_t length);
static StaticQueue_t tx_queue;
static uint8_t tx_q_buffer[J1939_SEND_QUEUE_SIZE * sizeof(j1939_output_msg_info_t)];
static StaticQueue_t rx_queue;
static uint8_t rx_q_buffer[J1939_RECV_QUEUE_SIZE * CAN_MTU];

static uint8_t tx_buffer[J1939_TX_BUFFER_SIZE];
static uint8_t rx_buffer[J1939_TX_BUFFER_SIZE];

static EventGroupHandle_t j1939_init_event;

static j1939_pgn_table_t j1939tp_pgn_table[] = {
    [0] = {.pgn = 0xE300, .handle_func = &can_ch0_recv_callback},
    [1] = {.pgn = 0xEB00, .handle_func = &can_ch0_recv_callback},
    [2] = {.pgn = 0xEC00, .handle_func = &can_ch0_recv_callback},
    [3] = {.pgn = 0x200, .handle_func = &can_ch0_recv_callback},
    [4] = {.pgn = 0x600, .handle_func = &can_ch0_recv_callback},
    [5] = {.pgn = 0x900, .handle_func = &can_ch0_recv_callback},
    [6] = {.pgn = 0x1000, .handle_func = &can_ch0_recv_callback},
    [7] = {.pgn = 0x1100, .handle_func = &can_ch0_recv_callback},
    [8] = {.pgn = 0x1300, .handle_func = &can_ch0_recv_callback},
    [9] = {.pgn = 0x1500, .handle_func = &can_ch0_recv_callback},
    [10] = {.pgn = 0x1600, .handle_func = &can_ch0_recv_callback},
    [11] = {.pgn = 0x1700, .handle_func = &can_ch0_recv_callback},
    [12] = {.pgn = 0x1900, .handle_func = &can_ch0_recv_callback},
    [13] = {.pgn = 0x1C00, .handle_func = &can_ch0_recv_callback},
    [14] = {.pgn = 0x2700, .handle_func = &can_ch0_recv_callback},
    [15] = {.pgn = 0xA00, .handle_func = &can_ch0_recv_callback},
    [16] = {.pgn = 0x1E00, .handle_func = &can_ch0_recv_callback},
};

static j1939tp_config_t j1939tp_cfg_ch0 = {

    .chn = 0,
    .pgn_tab = j1939tp_pgn_table,
    .timeout_Tr = 10,
    .timeout_Th = 500,
    .timeout_T1 = 750,
    .timeout_T2 = 1250,
    .timeout_T3 = 1250,
    .timeout_T4 = 1050,
    .retransmit_max = 2,
    .tp_block = 16,
    .padding = 0xff,                /* 填充的默认值 */
    .rx_queue_size = 32,
    .rxqueue = &rx_queue,
    .rxq_storage = rx_q_buffer,
    .tx_queue_size = 16,
    .txqueue = &tx_queue,
    .txq_storage = tx_q_buffer,
    .pgn_num = 17                   /*接收的PGN表大小 */
};

/* 1939发送配置 */
static j1939tp_tx_sesssion_t j1939tp_tx_sesssion[] = {

    [0] = {.addr = 0x56, .buffer = tx_buffer, .max_len = 10, .max_bam_len = 36},
    [1] = {.addr = 0x66, .max_len = 10, .max_bam_len = 36},
    [2] = {.addr = 0x67, .max_len = 10, .max_bam_len = 36},
    [3] = {.addr = 0x68, .max_len = 10, .max_bam_len = 36},
};

static j1939tp_rx_sesssion_t j1939tp_rx_sesssion[] = {

    [0] = {.addr = 0xf4, .buffer = rx_buffer, .max_len = 64, .max_bam_len = 36},
};

static j1939tp_session_t j1939tp_session = {

    .rx = j1939tp_rx_sesssion,
    .rx_num = 1,
    .tx = j1939tp_tx_sesssion,
    .tx_num = 4};

static j1939tp_runtime_t j1939tp_bms_runtime = {

    .config = &j1939tp_cfg_ch0,
    .session = &j1939tp_session};

int j1939tp_config(void *arg)
{
    int ret = RT_EOK;

    return ret;
}

/* J1939的任务创建和初始化 */
int j1939_init(void)
{
    int ret = RT_EOK;
    TaskHandle_t j1939_tx_task, j1939_rx_task;

    j1939_init_event = xEventGroupCreate();
    /* 创建发送任务 */
    xTaskCreate(j1939tp_tx_task, "j1939_t", 2048 + 512, (void *)&j1939tp_bms_runtime, osPriorityRealtime2, &j1939_tx_task);
    /* 创建接收任务 */
    xTaskCreate(j1939tp_rx_task, "j1939_r", 2048 + 512, (void *)&j1939tp_bms_runtime, osPriorityRealtime2, &j1939_rx_task);
    return ret;
}

j1939tp_runtime_t *get_runtime(void)
{
    return &j1939tp_bms_runtime;
}

void j1939_set_event(uint32_t evt)
{
    xEventGroupSetBits(j1939_init_event, evt);
}

int j1939_init_ready(void)
{
    int ret = 0;
    EventBits_t uxBits = 0;
    const EventBits_t xBitsToWaitFor = J1939_TX_TASK_READY | J1939_RX_TASK_READY;
    const BaseType_t xClearOnExit = pdTRUE;
    const BaseType_t xWaitForAllBits = pdTRUE;              
    const TickType_t xTicksToWait = portMAX_DELAY;
    uxBits = xEventGroupWaitBits(j1939_init_event, xBitsToWaitFor, xClearOnExit, xWaitForAllBits, xTicksToWait);
    if (uxBits == xBitsToWaitFor)
    {
        ret = 1;
    }
    return ret;
}


